home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 2 / Apprentice-Release2.iso / Tools / MPW / GCC 1.37.1r15 / Machines / out-i860.c < prev    next >
Encoding:
C/C++ Source or Header  |  1990-03-14  |  37.2 KB  |  1,451 lines  |  [TEXT/MPS ]

  1. /* Subroutines for insn-output.c for Intel 860
  2.    Copyright (C) 1989 Free Software Foundation, Inc.
  3.    Derived from out-sparc.c.
  4.  
  5. This file is part of GNU CC.
  6.  
  7. GNU CC is free software; you can redistribute it and/or modify
  8. it under the terms of the GNU General Public License as published by
  9. the Free Software Foundation; either version 1, or (at your option)
  10. any later version.
  11.  
  12. GNU CC is distributed in the hope that it will be useful,
  13. but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  15. GNU General Public License for more details.
  16.  
  17. You should have received a copy of the GNU General Public License
  18. along with GNU CC; see the file COPYING.  If not, write to
  19. the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
  20.  
  21.  
  22. /* Global variables for machine-dependend things.  */
  23.  
  24. /* This should go away if we pass floats to regs via
  25.    the stack instead of the frame, and if we learn how
  26.    to renumber all the registers when we don't do a save (hard!).  */
  27. extern int frame_pointer_needed;
  28.  
  29. static rtx find_addr_reg ();
  30.  
  31. /* Return non-zero only if OP is a register of mode MODE,
  32.    or const0_rtx.  */
  33. int
  34. reg_or_0_operand (op, mode)
  35.      rtx op;
  36.      enum machine_mode mode;
  37. {
  38.   return (op == const0_rtx || register_operand (op, mode)
  39.       || op == CONST0_RTX (mode));
  40. }
  41.  
  42. /* Return non-zero if this pattern, can be evaluated safely, even if it
  43.    was not asked for.  */
  44. int
  45. safe_insn_src_p (op, mode)
  46.      rtx op;
  47.      enum machine_mode mode;
  48. {
  49.   /* Just experimenting.  */
  50.  
  51.   /* No floating point src is safe if it contains an arithmetic
  52.      operation, since that operation may trap.  */
  53.   switch (GET_CODE (op))
  54.     {
  55.     case CONST_INT:
  56.     case LABEL_REF:
  57.     case SYMBOL_REF:
  58.     case CONST:
  59.       return 1;
  60.  
  61.     case REG:
  62.       return 1;
  63.  
  64.     case MEM:
  65.       return CONSTANT_ADDRESS_P (XEXP (op, 0));
  66.  
  67.       /* We never need to negate or complement constants.  */
  68.     case NEG:
  69.       return (mode != SFmode && mode != DFmode);
  70.     case NOT:
  71.     case ZERO_EXTEND:
  72.       return 1;
  73.  
  74.     case EQ:
  75.     case NE:
  76.     case LT:
  77.     case GT:
  78.     case LE:
  79.     case GE:
  80.     case LTU:
  81.     case GTU:
  82.     case LEU:
  83.     case GEU:
  84.     case MINUS:
  85.     case PLUS:
  86.       return (mode != SFmode && mode != DFmode);
  87.     case AND:
  88.     case IOR:
  89.     case XOR:
  90.     case LSHIFT:
  91.     case ASHIFT:
  92.     case ASHIFTRT:
  93.     case LSHIFTRT:
  94.       if ((GET_CODE (XEXP (op, 0)) == CONST_INT && ! SMALL_INT (XEXP (op, 0)))
  95.       || (GET_CODE (XEXP (op, 1)) == CONST_INT && ! SMALL_INT (XEXP (op, 1))))
  96.     return 0;
  97.       return 1;
  98.  
  99.     default:
  100.       return 0;
  101.     }
  102. }
  103.  
  104. /* Return 1 if REG is clobbered in IN.
  105.    Return 2 if REG is used in IN. 
  106.    Return 3 if REG is both used and clobbered in IN.
  107.    Return 0 if neither.  */
  108.  
  109. static int
  110. reg_clobbered_p (reg, in)
  111.      rtx reg;
  112.      rtx in;
  113. {
  114.   register enum rtx_code code;
  115.  
  116.   if (in == 0)
  117.     return 0;
  118.  
  119.   code = GET_CODE (in);
  120.  
  121.   if (code == SET || code == CLOBBER)
  122.     {
  123.       rtx dest = SET_DEST (in);
  124.       int set = 0;
  125.       int used = 0;
  126.  
  127.       while (GET_CODE (dest) == STRICT_LOW_PART
  128.          || GET_CODE (dest) == SUBREG
  129.          || GET_CODE (dest) == SIGN_EXTRACT
  130.          || GET_CODE (dest) == ZERO_EXTRACT)
  131.     dest = XEXP (dest, 0);
  132.  
  133.       if (dest == reg)
  134.     set = 1;
  135.       else if (GET_CODE (dest) == REG
  136.            && refers_to_regno_p (REGNO (reg),
  137.                      REGNO (reg) + HARD_REGNO_NREGS (reg, GET_MODE (reg)),
  138.                      SET_DEST (in), 0))
  139.     {
  140.       set = 1;
  141.       /* Anything that sets just part of the register
  142.          is considered using as well as setting it.
  143.          But note that a straight SUBREG of a single-word value
  144.          clobbers the entire value.   */
  145.       if (dest != SET_DEST (in)
  146.           && ! (GET_CODE (SET_DEST (in)) == SUBREG
  147.             || UNITS_PER_WORD >= GET_MODE_SIZE (GET_MODE (dest))))
  148.         used = 1;
  149.     }
  150.  
  151.       if (code == SET)
  152.     {
  153.       if (set)
  154.         used = refers_to_regno_p (REGNO (reg),
  155.                       REGNO (reg) + HARD_REGNO_NREGS (reg, GET_MODE (reg)),
  156.                       SET_SRC (in), 0);
  157.       else
  158.         used = refers_to_regno_p (REGNO (reg),
  159.                       REGNO (reg) + HARD_REGNO_NREGS (reg, GET_MODE (reg)),
  160.                       in, 0);
  161.     }
  162.  
  163.       return set + used * 2;
  164.     }
  165.  
  166.   if (refers_to_regno_p (REGNO (reg),
  167.              REGNO (reg) + HARD_REGNO_NREGS (reg, GET_MODE (reg)),
  168.              in, 0))
  169.     return 2;
  170.   return 0;
  171. }
  172.  
  173. /* Return non-zero if OP can be written to without screwing up
  174.    GCC's model of what's going on.  It is assumed that this operand
  175.    appears in the dest position of a SET insn in a conditional
  176.    branch's delay slot.  AFTER is the label to start looking from.  */
  177. int
  178. operand_clobbered_before_used_after (op, after)
  179.      rtx op;
  180.      rtx after;
  181. {
  182.   extern char call_used_regs[];
  183.  
  184.   /* Just experimenting.  */
  185.   if (GET_CODE (op) == CC0)
  186.     return 1;
  187.   if (GET_CODE (op) == REG)
  188.     {
  189.       rtx insn;
  190.  
  191.       if (op == stack_pointer_rtx)
  192.     return 0;
  193.  
  194.       /* Scan forward from the label, to see if the value of OP
  195.      is clobbered before the first use.  */
  196.  
  197.       for (insn = NEXT_INSN (after); insn; insn = NEXT_INSN (insn))
  198.     {
  199.       if (GET_CODE (insn) == NOTE)
  200.         continue;
  201.       if (GET_CODE (insn) == INSN
  202.           || GET_CODE (insn) == JUMP_INSN
  203.           || GET_CODE (insn) == CALL_INSN)
  204.         {
  205.           switch (reg_clobbered_p (op, PATTERN (insn)))
  206.         {
  207.         default:
  208.           return 0;
  209.         case 1:
  210.           return 1;
  211.         case 0:
  212.           break;
  213.         }
  214.         }
  215.       /* If we reach another label without clobbering OP,
  216.          then we cannot safely write it here.  */
  217.       else if (GET_CODE (insn) == CODE_LABEL)
  218.         return 0;
  219.       if (GET_CODE (insn) == JUMP_INSN)
  220.         {
  221.           if (condjump_p (insn))
  222.         return 0;
  223.           /* This is a jump insn which has already
  224.          been mangled.  We can't tell what it does.  */
  225.           if (GET_CODE (PATTERN (insn)) == PARALLEL)
  226.         return 0;
  227.           if (! JUMP_LABEL (insn))
  228.         return 0;
  229.           /* Keep following jumps.  */
  230.           insn = JUMP_LABEL (insn);
  231.         }
  232.     }
  233.       return 1;
  234.     }
  235.  
  236.   /* In both of these cases, the first insn executed
  237.      for this op will be a orh whatever%h,r0,r31,
  238.      which is tolerable.  */
  239.   if (GET_CODE (op) == MEM)
  240.     return (CONSTANT_ADDRESS_P (XEXP (op, 0)));
  241.  
  242.   return 0;
  243. }
  244.  
  245. /* Return non-zero if this pattern, as a source to a "SET",
  246.    is known to yield an instruction of unit size.  */
  247. int
  248. single_insn_src_p (op, mode)
  249.      rtx op;
  250.      enum machine_mode mode;
  251. {
  252.   switch (GET_CODE (op))
  253.     {
  254.     case CONST_INT:
  255.       /* This is not always a single insn src, technically,
  256.      but output_delayed_branch knows how to deal with it.  */
  257.       return 1;
  258.  
  259.     case SYMBOL_REF:
  260.     case CONST:
  261.       /* This is not a single insn src, technically,
  262.      but output_delayed_branch knows how to deal with it.  */
  263.       return 1;
  264.  
  265.     case REG:
  266.       return 1;
  267.  
  268.     case MEM:
  269.       return 1;
  270.  
  271.       /* We never need to negate or complement constants.  */
  272.     case NEG:
  273.       return (mode != DFmode);
  274.     case NOT:
  275.     case ZERO_EXTEND:
  276.       return 1;
  277.  
  278.     case EQ:
  279.     case NE:
  280.     case LT:
  281.     case GT:
  282.     case LE:
  283.     case GE:
  284.     case LTU:
  285.     case GTU:
  286.     case LEU:
  287.     case GEU:
  288.     case MINUS:
  289.     case PLUS:
  290.       /* Not doing floating point, since they probably
  291.      take longer than the branch slot they might fill.  */
  292.       return (mode != SFmode && mode != DFmode);
  293.     case AND:
  294.     case IOR:
  295.     case XOR:
  296.     case LSHIFT:
  297.     case ASHIFT:
  298.     case ASHIFTRT:
  299.     case LSHIFTRT:
  300.       if ((GET_CODE (XEXP (op, 0)) == CONST_INT && ! SMALL_INT (XEXP (op, 0)))
  301.       || (GET_CODE (XEXP (op, 1)) == CONST_INT && ! SMALL_INT (XEXP (op, 1))))
  302.     return 0;
  303.       return 1;
  304.  
  305.     case SUBREG:
  306.       if (SUBREG_WORD (op) != 0)
  307.     return 0;
  308.       return single_insn_src_p (SUBREG_REG (op), mode);
  309.  
  310.       /* Not doing floating point, since they probably
  311.      take longer than the branch slot they might fill.  */
  312.     case FLOAT_EXTEND:
  313.     case FLOAT_TRUNCATE:
  314.     case FLOAT:
  315.     case FIX:
  316.     case UNSIGNED_FLOAT:
  317.     case UNSIGNED_FIX:
  318.       return 0;
  319.  
  320.     default:
  321.       return 0;
  322.     }
  323. }
  324.  
  325. /* Nonzero only if this *really* is a single insn operand.  */
  326. int
  327. strict_single_insn_op_p (op, mode)
  328.      rtx op;
  329.      enum machine_mode mode;
  330. {
  331.   if (mode == VOIDmode)
  332.     mode = GET_MODE (op);
  333.  
  334.   switch (GET_CODE (op))
  335.     {
  336.     case CC0:
  337.       return 1;
  338.  
  339.     case CONST_INT:
  340.       if (SMALL_INT (op))
  341.     return 1;
  342.       /* We can put this set insn into delay slot, because this is one
  343.      insn; 'sethi'.  */
  344.       if ((INTVAL (op) & 0x3ff) == 0)
  345.     return 1;
  346.       return 0;
  347.  
  348.     case SYMBOL_REF:
  349.       return 0;
  350.  
  351.     case REG:
  352. #if 0
  353.       /* This loses when moving an freg to a general reg.  */
  354.       return HARD_REGNO_NREGS (REGNO (op), mode) == 1;
  355. #endif
  356.       return (mode != DFmode && mode != DImode);
  357.  
  358.     case MEM:
  359.       if (! CONSTANT_ADDRESS_P (XEXP (op, 0)))
  360.     return (mode != DFmode && mode != DImode);
  361.       return 0;
  362.  
  363.       /* We never need to negate or complement constants.  */
  364.     case NEG:
  365.       return (mode != DFmode);
  366.     case NOT:
  367.     case ZERO_EXTEND:
  368.       return 1;
  369.  
  370.     case EQ:
  371.     case NE:
  372.     case LT:
  373.     case GT:
  374.     case LE:
  375.     case GE:
  376.     case LTU:
  377.     case GTU:
  378.     case LEU:
  379.     case GEU:
  380.     case MINUS:
  381.     case PLUS:
  382.     case AND:
  383.     case IOR:
  384.     case XOR:
  385.     case LSHIFT:
  386.     case ASHIFT:
  387.     case ASHIFTRT:
  388.     case LSHIFTRT:
  389.       if ((GET_CODE (XEXP (op, 0)) == CONST_INT && ! SMALL_INT (XEXP (op, 0)))
  390.       || (GET_CODE (XEXP (op, 1)) == CONST_INT && ! SMALL_INT (XEXP (op, 1))))
  391.     return 0;
  392.       return 1;
  393.  
  394.     case SUBREG:
  395.       if (SUBREG_WORD (op) != 0)
  396.     return 0;
  397.       return strict_single_insn_op_p (SUBREG_REG (op), mode);
  398.  
  399.     case SIGN_EXTEND:
  400.       if (GET_CODE (XEXP (op, 0)) == MEM
  401.       && ! CONSTANT_ADDRESS_P (XEXP (XEXP (op, 0), 0)))
  402.     return 1;
  403.       return 0;
  404.  
  405.       /* Not doing floating point, since they probably
  406.      take longer than the branch slot they might fill.  */
  407.     case FLOAT_EXTEND:
  408.     case FLOAT_TRUNCATE:
  409.     case FLOAT:
  410.     case FIX:
  411.     case UNSIGNED_FLOAT:
  412.     case UNSIGNED_FIX:
  413.       return 0;
  414.  
  415.     default:
  416.       return 0;
  417.     }
  418. }
  419.  
  420. /* Return truth value of whether OP is a relational operator.  */
  421. int
  422. relop (op, mode)
  423.      rtx op;
  424.      enum machine_mode mode;
  425. {
  426.   switch (GET_CODE (op))
  427.     {
  428.     case EQ:
  429.     case NE:
  430.     case GT:
  431.     case GE:
  432.     case LT:
  433.     case LE:
  434.     case GTU:
  435.     case GEU:
  436.     case LTU:
  437.     case LEU:
  438.       return 1;
  439.     }
  440.   return 0;
  441. }
  442.  
  443. /* Return truth value of whether OP can be used as an operands in a three
  444.    address add/subtract insn (such as add %o1,7,%l2) of mode MODE.  */
  445.  
  446. int
  447. arith_operand (op, mode)
  448.      rtx op;
  449.      enum machine_mode mode;
  450. {
  451.   return (register_operand (op, mode)
  452.       || (GET_CODE (op) == CONST_INT && SMALL_INT (op)));
  453. }
  454.  
  455. /* Return 1 if OP is a valid first operand for a logical insn of mode MODE.  */
  456.  
  457. int
  458. logic_operand (op, mode)
  459.      rtx op;
  460.      enum machine_mode mode;
  461. {
  462.   return (register_operand (op, mode)
  463.       || (GET_CODE (op) == CONST_INT && LOGIC_INT (op)));
  464. }
  465.  
  466. /* Return 1 if OP is a valid first operand for either a logical insn
  467.    or an add insn of mode MODE.  */
  468.  
  469. int
  470. compare_operand (op, mode)
  471.      rtx op;
  472.      enum machine_mode mode;
  473. {
  474.   return (register_operand (op, mode)
  475.       || (GET_CODE (op) == CONST_INT && SMALL_INT (op) && LOGIC_INT (op)));
  476. }
  477.  
  478. /* Return truth value of whether OP can be used as an operand
  479.    of a bte insn.  */
  480.  
  481. int
  482. bte_operand (op, mode)
  483.      rtx op;
  484.      enum machine_mode mode;
  485. {
  486.   return (register_operand (op, mode)
  487.       || (GET_CODE (op) == CONST_INT
  488.           && (unsigned) INTVAL (op) < 0x20));
  489. }
  490.  
  491. /* Return 1 if OP is an indexed memory reference of mode MODE.  */
  492.  
  493. int
  494. indexed_operand (op, mode)
  495.      rtx op;
  496.      enum machine_mode mode;
  497. {
  498.   return (GET_CODE (op) == MEM && GET_MODE (op) == mode
  499.       && GET_CODE (XEXP (op, 0)) == PLUS
  500.       && GET_MODE (XEXP (op, 0)) == SImode
  501.       && register_operand (XEXP (XEXP (op, 0), 0), SImode)
  502.       && register_operand (XEXP (XEXP (op, 0), 1), SImode));
  503. }
  504.  
  505. /* Return 1 if OP is a suitable source operand for a load insn
  506.    with mode MODE.  */
  507.  
  508. int
  509. load_operand (op, mode)
  510.      rtx op;
  511.      enum machine_mode mode;
  512. {
  513.   return (memory_operand (op, mode) || indexed_operand (op, mode));
  514. }
  515.  
  516. /* Return truth value of whether OP is a integer which fits the
  517.    range constraining immediate operands in add/subtract insns.  */
  518.  
  519. int
  520. small_int (op, mode)
  521.      rtx op;
  522.      enum machine_mode mode;
  523. {
  524.   return (GET_CODE (op) == CONST_INT && SMALL_INT (op));
  525. }
  526.  
  527. /* Return truth value of whether OP is a integer which fits the
  528.    range constraining immediate operands in logic insns.  */
  529.  
  530. int
  531. logic_int (op, mode)
  532.      rtx op;
  533.      enum machine_mode mode;
  534. {
  535.   return (GET_CODE (op) == CONST_INT && LOGIC_INT (op));
  536. }
  537.  
  538. /* Return the best assembler insn template
  539.    for moving operands[1] into operands[0] as a fullword.  */
  540.  
  541. static char *
  542. singlemove_string (operands)
  543.      rtx *operands;
  544. {
  545.   if (GET_CODE (operands[0]) == MEM)
  546.     {
  547.       if (GET_CODE (operands[1]) != MEM)
  548.     if (CONSTANT_ADDRESS_P (XEXP (operands[0], 0)))
  549.       {
  550.         if (! ((cc_prev_status.flags & CC_KNOW_HI_R31)
  551.            && (cc_prev_status.flags & CC_HI_R31_ADJ)
  552.            && cc_prev_status.mdep == XEXP (operands[0], 0)))
  553.           output_asm_insn ("orh ha%%%m0,r0,r31", operands);
  554.         cc_status.flags |= CC_KNOW_HI_R31 | CC_HI_R31_ADJ;
  555.         cc_status.mdep = XEXP (operands[0], 0);
  556.         return "st.l %r1,l%%%m0(r31)";
  557.       }
  558.     else
  559.       return "st.l %r1,%0";
  560.       else
  561.     abort ();
  562. #if 0
  563.     {
  564.       rtx xoperands[2];
  565.  
  566.       cc_status.flags &= ~CC_F0_IS_0;
  567.       xoperands[0] = gen_rtx (REG, SFmode, 32);
  568.       xoperands[1] = operands[1];
  569.       output_asm_insn (singlemove_string (xoperands), xoperands);
  570.       xoperands[1] = xoperands[0];
  571.       xoperands[0] = operands[0];
  572.       output_asm_insn (singlemove_string (xoperands), xoperands);
  573.       return "";
  574.     }
  575. #endif
  576.     }
  577.   if (GET_CODE (operands[1]) == MEM)
  578.     {
  579.       if (CONSTANT_ADDRESS_P (XEXP (operands[1], 0)))
  580.     {
  581.       if (! ((cc_prev_status.flags & CC_KNOW_HI_R31)
  582.          && (cc_prev_status.flags & CC_HI_R31_ADJ)
  583.          && cc_prev_status.mdep == XEXP (operands[1], 0)))
  584.         output_asm_insn ("orh ha%%%m1,r0,r31", operands);
  585.       cc_status.flags |= CC_KNOW_HI_R31 | CC_HI_R31_ADJ;
  586.       cc_status.mdep = XEXP (operands[1], 0);
  587.       return "ld.l l%%%m1(r31),%0";
  588.     }
  589.       return "ld.l %1,%0";
  590.     }
  591.   return "mov %1,%0";
  592. }
  593.  
  594. /* Output assembler code to perform a doubleword move insn
  595.    with operands OPERANDS.  */
  596.  
  597. char *
  598. output_move_double (operands)
  599.      rtx *operands;
  600. {
  601.   enum { REGOP, OFFSOP, MEMOP, PUSHOP, POPOP, CNSTOP, RNDOP } optype0, optype1;
  602.   rtx latehalf[2];
  603.   rtx addreg0 = 0, addreg1 = 0;
  604.  
  605.   /* First classify both operands.  */
  606.  
  607.   if (REG_P (operands[0]))
  608.     optype0 = REGOP;
  609.   else if (offsettable_memref_p (operands[0]))
  610.     optype0 = OFFSOP;
  611.   else if (GET_CODE (operands[0]) == MEM)
  612.     optype0 = MEMOP;
  613.   else
  614.     optype0 = RNDOP;
  615.  
  616.   if (REG_P (operands[1]))
  617.     optype1 = REGOP;
  618.   else if (CONSTANT_P (operands[1])
  619.        || GET_CODE (operands[1]) == CONST_DOUBLE)
  620.     optype1 = CNSTOP;
  621.   else if (offsettable_memref_p (operands[1]))
  622.     optype1 = OFFSOP;
  623.   else if (GET_CODE (operands[1]) == MEM)
  624.     optype1 = MEMOP;
  625.   else
  626.     optype1 = RNDOP;
  627.  
  628.   /* Check for the cases that the operand constraints are not
  629.      supposed to allow to happen.  Abort if we get one,
  630.      because generating code for these cases is painful.  */
  631.  
  632.   if (optype0 == RNDOP || optype1 == RNDOP)
  633.     abort ();
  634.  
  635.   /* If an operand is an unoffsettable memory ref, find a register
  636.      we can increment temporarily to make it refer to the second word.  */
  637.  
  638.   if (optype0 == MEMOP)
  639.     addreg0 = find_addr_reg (XEXP (operands[0], 0));
  640.  
  641.   if (optype1 == MEMOP)
  642.     addreg1 = find_addr_reg (XEXP (operands[1], 0));
  643.  
  644. /* ??? Perhaps in some cases move double words
  645.    if there is a spare pair of floating regs.  */
  646.  
  647.   /* Ok, we can do one word at a time.
  648.      Normally we do the low-numbered word first,
  649.      but if either operand is autodecrementing then we
  650.      do the high-numbered word first.
  651.  
  652.      In either case, set up in LATEHALF the operands to use
  653.      for the high-numbered word and in some cases alter the
  654.      operands in OPERANDS to be suitable for the low-numbered word.  */
  655.  
  656.   if (optype0 == REGOP)
  657.     latehalf[0] = gen_rtx (REG, SImode, REGNO (operands[0]) + 1);
  658.   else if (optype0 == OFFSOP)
  659.     latehalf[0] = adj_offsettable_operand (operands[0], 4);
  660.   else
  661.     latehalf[0] = operands[0];
  662.  
  663.   if (optype1 == REGOP)
  664.     latehalf[1] = gen_rtx (REG, SImode, REGNO (operands[1]) + 1);
  665.   else if (optype1 == OFFSOP)
  666.     latehalf[1] = adj_offsettable_operand (operands[1], 4);
  667.   else if (optype1 == CNSTOP)
  668.     {
  669.       if (CONSTANT_P (operands[1]))
  670.     latehalf[1] = const0_rtx;
  671.       else if (GET_CODE (operands[1]) == CONST_DOUBLE)
  672.     {
  673.       latehalf[1] = gen_rtx (CONST_INT, VOIDmode,
  674.                  CONST_DOUBLE_HIGH (operands[1]));
  675.       operands[1] = gen_rtx (CONST_INT, VOIDmode,
  676.                  CONST_DOUBLE_LOW (operands[1]));
  677.     }
  678.     }
  679.   else
  680.     latehalf[1] = operands[1];
  681.  
  682.   /* If the first move would clobber the source of the second one,
  683.      do them in the other order.
  684.  
  685.      RMS says "This happens only for registers;
  686.      such overlap can't happen in memory unless the user explicitly
  687.      sets it up, and that is an undefined circumstance."
  688.  
  689.      but it happens on the sparc when loading parameter registers,
  690.      so I am going to define that circumstance, and make it work
  691.      as expected.  */
  692.  
  693.   if (optype0 == REGOP && optype1 == REGOP
  694.       && REGNO (operands[0]) == REGNO (latehalf[1]))
  695.     {
  696.       /* Make any unoffsettable addresses point at high-numbered word.  */
  697.       if (addreg0)
  698.     output_asm_insn ("adds 0x4,%0,%0", &addreg0);
  699.       if (addreg1)
  700.     output_asm_insn ("adds 0x4,%0,%0", &addreg1);
  701.  
  702.       /* Do that word.  */
  703.       output_asm_insn (singlemove_string (latehalf), latehalf);
  704.  
  705.       /* Undo the adds we just did.  */
  706.       if (addreg0)
  707.     output_asm_insn ("adds -0x4,%0,%0", &addreg0);
  708.       if (addreg1)
  709.     output_asm_insn ("adds -0x4,%0,%0", &addreg1);
  710.  
  711.       /* Do low-numbered word.  */
  712.       return singlemove_string (operands);
  713.     }
  714.   else if (optype0 == REGOP && optype1 != REGOP
  715.        && reg_overlap_mentioned_p (operands[0], operands[1]))
  716.     {
  717.       /* Do the late half first.  */
  718.       output_asm_insn (singlemove_string (latehalf), latehalf);
  719.       /* Then clobber.  */
  720.       return singlemove_string (operands);
  721.     }
  722.  
  723.   /* Normal case: do the two words, low-numbered first.  */
  724.  
  725.   output_asm_insn (singlemove_string (operands), operands);
  726.  
  727.   /* Make any unoffsettable addresses point at high-numbered word.  */
  728.   if (addreg0)
  729.     output_asm_insn ("adds 0x4,%0,%0", &addreg0);
  730.   if (addreg1)
  731.     output_asm_insn ("adds 0x4,%0,%0", &addreg1);
  732.  
  733.   /* Do that word.  */
  734.   output_asm_insn (singlemove_string (latehalf), latehalf);
  735.  
  736.   /* Undo the adds we just did.  */
  737.   if (addreg0)
  738.     output_asm_insn ("adds -0x4,%0,%0", &addreg0);
  739.   if (addreg1)
  740.     output_asm_insn ("adds -0x4,%0,%0", &addreg1);
  741.  
  742.   return "";
  743. }
  744.  
  745. static char *
  746. output_fp_move_double (operands)
  747.      rtx *operands;
  748. {
  749.   if (FP_REG_P (operands[0]))
  750.     {
  751.       if (FP_REG_P (operands[1]))
  752.     return "fmov.dd %1,%0";
  753.       if (GET_CODE (operands[1]) == REG)
  754.     {
  755.       output_asm_insn ("ixfr %1,%0", operands);
  756.       operands[0] = gen_rtx (REG, VOIDmode, REGNO (operands[0]) + 1);
  757.       operands[1] = gen_rtx (REG, VOIDmode, REGNO (operands[1]) + 1);
  758.       return "ixfr %1,%0";
  759.     }
  760.       if (operands[1] == dconst0_rtx)
  761.     return "fmov.dd f0,%0";
  762.       if (CONSTANT_ADDRESS_P (XEXP (operands[1], 0)))
  763.     {
  764.       if (! ((cc_prev_status.flags & CC_KNOW_HI_R31)
  765.          && (cc_prev_status.flags & CC_HI_R31_ADJ)
  766.          && cc_prev_status.mdep == XEXP (operands[1], 0)))
  767.         output_asm_insn ("orh ha%%%m1,r0,r31", operands);
  768.       cc_status.flags |= CC_KNOW_HI_R31 | CC_HI_R31_ADJ;
  769.       cc_status.mdep = XEXP (operands[1], 0);
  770.       return "fld.d l%%%m1(r31),%0";
  771.     }
  772.       return "fld.d %1,%0";
  773.     }
  774.   else if (FP_REG_P (operands[1]))
  775.     {
  776.       if (GET_CODE (operands[0]) == REG)
  777.     {
  778.       output_asm_insn ("fxfr %1,%0", operands);
  779.       operands[0] = gen_rtx (REG, VOIDmode, REGNO (operands[0]) + 1);
  780.       operands[1] = gen_rtx (REG, VOIDmode, REGNO (operands[1]) + 1);
  781.       return "fxfr %1,%0";
  782.     }
  783.       if (CONSTANT_ADDRESS_P (XEXP (operands[0], 0)))
  784.     {
  785.       if (! ((cc_prev_status.flags & CC_KNOW_HI_R31)
  786.          && (cc_prev_status.flags & CC_HI_R31_ADJ)
  787.          && cc_prev_status.mdep == XEXP (operands[0], 0)))
  788.         output_asm_insn ("orh ha%%%m0,r0,r31", operands);
  789.       cc_status.flags |= CC_KNOW_HI_R31 | CC_HI_R31_ADJ;
  790.       cc_status.mdep = XEXP (operands[0], 0);
  791.       return "fst.d %1,l%%%m0(r31)";
  792.     }
  793.       return "fst.d %1,%0";
  794.     }
  795.   else abort ();
  796. }
  797.  
  798. /* Return a REG that occurs in ADDR with coefficient 1.
  799.    ADDR can be effectively incremented by incrementing REG.  */
  800.  
  801. static rtx
  802. find_addr_reg (addr)
  803.      rtx addr;
  804. {
  805.   while (GET_CODE (addr) == PLUS)
  806.     {
  807.       if (GET_CODE (XEXP (addr, 0)) == REG)
  808.     addr = XEXP (addr, 0);
  809.       else if (GET_CODE (XEXP (addr, 1)) == REG)
  810.     addr = XEXP (addr, 1);
  811.       else if (CONSTANT_P (XEXP (addr, 0)))
  812.     addr = XEXP (addr, 1);
  813.       else if (CONSTANT_P (XEXP (addr, 1)))
  814.     addr = XEXP (addr, 0);
  815.       else
  816.     abort ();
  817.     }
  818.   if (GET_CODE (addr) == REG)
  819.     return addr;
  820.   abort ();
  821. }
  822.  
  823. /* Return a template for a load instruction with mode MODE and
  824.    arguments from the string ARGS.
  825.  
  826.    This string is in static storage.   */
  827.  
  828. static char *
  829. load_opcode (mode, args, reg)
  830.      enum machine_mode mode;
  831.      char *args;
  832.      rtx reg;
  833. {
  834.   static char buf[30];
  835.   char *opcode;
  836.  
  837.   switch (mode)
  838.     {
  839.     case QImode:
  840.       opcode = "ld.b";
  841.       break;
  842.  
  843.     case HImode:
  844.       opcode = "ld.s";
  845.       break;
  846.  
  847.     case SImode:
  848.     case SFmode:
  849.       if (FP_REG_P (reg))
  850.     opcode = "fld.l";
  851.       else
  852.     opcode = "ld.l";
  853.       break;
  854.  
  855.     case DImode:
  856.       if (!FP_REG_P (reg))
  857.     abort ();
  858.     case DFmode:
  859.       opcode = "fld.d";
  860.       break;
  861.  
  862.     default:
  863.       abort ();
  864.     }
  865.  
  866.   sprintf (buf, "%s %s", opcode, args);
  867.   return buf;
  868. }
  869.  
  870. /* Return a template for a store instruction with mode MODE and
  871.    arguments from the string ARGS.
  872.  
  873.    This string is in static storage.   */
  874.  
  875. static char *
  876. store_opcode (mode, args, reg)
  877.      enum machine_mode mode;
  878.      char *args;
  879.      rtx reg;
  880. {
  881.   static char buf[30];
  882.   char *opcode;
  883.  
  884.   switch (mode)
  885.     {
  886.     case QImode:
  887.       opcode = "st.b";
  888.       break;
  889.  
  890.     case HImode:
  891.       opcode = "st.s";
  892.       break;
  893.  
  894.     case SImode:
  895.     case SFmode:
  896.       if (FP_REG_P (reg))
  897.     opcode = "fst.l";
  898.       else
  899.     opcode = "st.l";
  900.       break;
  901.  
  902.     case DImode:
  903.       if (!FP_REG_P (reg))
  904.     abort ();
  905.     case DFmode:
  906.       opcode = "fst.d";
  907.       break;
  908.  
  909.     default:
  910.       abort ();
  911.     }
  912.  
  913.   sprintf (buf, "%s %s", opcode, args);
  914.   return buf;
  915. }
  916.  
  917. /* Output a store-in-memory whose operands are OPERANDS[0,1].
  918.    OPERANDS[0] is a MEM, and OPERANDS[1] is a reg or zero.
  919.  
  920.    This function returns a template for an insn.
  921.    This is in static storage.
  922.  
  923.    It may also output some insns directly.
  924.    It may alter the values of operands[0] and operands[1].  */
  925.  
  926. char *
  927. output_store (operands)
  928.      rtx *operands;
  929. {
  930.   enum machine_mode mode = GET_MODE (operands[0]);
  931.   rtx address = XEXP (operands[0], 0);
  932.   char *string;
  933.  
  934.   cc_status.flags |= CC_KNOW_HI_R31 | CC_HI_R31_ADJ;
  935.   cc_status.mdep = address;
  936.  
  937.   if (! ((cc_prev_status.flags & CC_KNOW_HI_R31)
  938.      && (cc_prev_status.flags & CC_HI_R31_ADJ)
  939.      && address == cc_prev_status.mdep))
  940.     {
  941.       output_asm_insn ("orh ha%%%m0,r0,r31", operands);
  942.       cc_prev_status.mdep = address;
  943.     }
  944.  
  945.   /* Store zero in two parts when appropriate.  */
  946.   if (mode == DFmode && operands[1] == dconst0_rtx)
  947.     return store_opcode (DFmode, "%r1,l%%%m0(r31)", operands[1]);
  948.  
  949.   /* Code below isn't smart enough to move a doubleword in two parts,
  950.      so use output_move_double to do that in the cases that require it.  */
  951.   if ((mode == DImode || mode == DFmode)
  952.       && ! FP_REG_P (operands[1]))
  953.     return output_move_double (operands);
  954.  
  955.   return store_opcode (mode, "%r1,l%%%m0(r31)", operands[1]);
  956. }
  957.  
  958. /* Output a load-from-memory whose operands are OPERANDS[0,1].
  959.    OPERANDS[0] is a reg, and OPERANDS[1] is a mem.
  960.  
  961.    This function returns a template for an insn.
  962.    This is in static storage.
  963.  
  964.    It may also output some insns directly.
  965.    It may alter the values of operands[0] and operands[1].  */
  966.  
  967. char *
  968. output_load (operands)
  969.      rtx *operands;
  970. {
  971.   enum machine_mode mode = GET_MODE (operands[0]);
  972.   rtx address = XEXP (operands[1], 0);
  973.  
  974.   /* We don't bother trying to see if we know %hi(address).
  975.      This is because we are doing a load, and if we know the
  976.      %hi value, we probably also know that value in memory.  */
  977.   cc_status.flags |= CC_KNOW_HI_R31 | CC_HI_R31_ADJ;
  978.   cc_status.mdep = address;
  979.  
  980.   if (! ((cc_prev_status.flags & CC_KNOW_HI_R31)
  981.      && (cc_prev_status.flags & CC_HI_R31_ADJ)
  982.      && address == cc_prev_status.mdep
  983.      && cc_prev_status.mdep == cc_status.mdep))
  984.     {
  985.       output_asm_insn ("orh ha%%%m1,r0,r31", operands);
  986.       cc_prev_status.mdep = address;
  987.     }
  988.  
  989.   /* Code below isn't smart enough to move a doubleword in two parts,
  990.      so use output_move_double to do that in the cases that require it.  */
  991.   if ((mode == DImode || mode == DFmode)
  992.       && ! FP_REG_P (operands[0]))
  993.     return output_move_double (operands);
  994.  
  995.   return load_opcode (mode, "l%%%m1(r31),%0", operands[0]);
  996. }
  997.  
  998. /* Load the address specified by OPERANDS[3] into the register
  999.    specified by OPERANDS[0].
  1000.  
  1001.    OPERANDS[3] may be the result of a sum, hence it could either be:
  1002.  
  1003.    (1) CONST
  1004.    (2) REG
  1005.    (2) REG + CONST_INT
  1006.    (3) REG + REG + CONST_INT
  1007.    (4) REG + REG  (special case of 3).
  1008.  
  1009.    Note that (3) is not a legitimate address.
  1010.    All cases are handled here.  */
  1011.  
  1012. void
  1013. output_load_address (operands)
  1014.      rtx *operands;
  1015. {
  1016.   rtx base, offset;
  1017.  
  1018.   if (CONSTANT_P (operands[3]))
  1019.     {
  1020.       output_asm_insn ("mov %3,%0", operands);
  1021.       return;
  1022.     }
  1023.  
  1024.   if (REG_P (operands[3]))
  1025.     {
  1026.       if (REGNO (operands[0]) != REGNO (operands[3]))
  1027.     output_asm_insn ("mov %3,%0", operands);
  1028.       return;
  1029.     }
  1030.  
  1031.   if (GET_CODE (operands[3]) != PLUS)
  1032.     abort ();
  1033.  
  1034.   base = XEXP (operands[3], 0);
  1035.   offset = XEXP (operands[3], 1);
  1036.  
  1037.   if (GET_CODE (base) == CONST_INT)
  1038.     {
  1039.       rtx tmp = base;
  1040.       base = offset;
  1041.       offset = tmp;
  1042.     }
  1043.  
  1044.   if (GET_CODE (offset) != CONST_INT)
  1045.     {
  1046.       /* Operand is (PLUS (REG) (REG)).  */
  1047.       base = operands[3];
  1048.       offset = const0_rtx;
  1049.     }
  1050.  
  1051.   if (REG_P (base))
  1052.     {
  1053.       operands[6] = base;
  1054.       operands[7] = offset;
  1055.       if (SMALL_INT (offset))
  1056.     output_asm_insn ("adds %7,%6,%0", operands);
  1057.       else
  1058.     output_asm_insn ("mov %7,%0\n\tadds %0,%6,%0", operands);
  1059.     }
  1060.   else if (GET_CODE (base) == PLUS)
  1061.     {
  1062.       operands[6] = XEXP (base, 0);
  1063.       operands[7] = XEXP (base, 1);
  1064.       operands[8] = offset;
  1065.  
  1066.       if (SMALL_INT (offset))
  1067.     output_asm_insn ("adds %6,%7,%0\n\tadds %8,%0,%0", operands);
  1068.       else
  1069.     output_asm_insn ("mov %8,%0\n\tadds %0,%6,%0\n\tadds %0,%7,%0", operands);
  1070.     }
  1071.   else
  1072.     abort ();
  1073. }
  1074.  
  1075. /* Output code to place a size count SIZE in register REG.
  1076.    Because block moves are pipelined, we don't include the
  1077.    first element in the transfer of SIZE to REG.
  1078.    For this, we subtract ALIGN.  (Actually, I think it is not
  1079.    right to subtract on this machine, so right now we don't.)  */
  1080.  
  1081. static void
  1082. output_size_for_block_move (size, reg, align)
  1083.      rtx size, reg, align;
  1084. {
  1085.   rtx xoperands[3];
  1086.  
  1087.   xoperands[0] = reg;
  1088.   xoperands[1] = size;
  1089.   xoperands[2] = align;
  1090.  
  1091. #if 1
  1092.   cc_status.flags &= ~ CC_KNOW_HI_R31;
  1093.   output_asm_insn ("mov %1,%0", xoperands);
  1094. #else
  1095.   if (GET_CODE (size) == REG)
  1096.     output_asm_insn ("sub %2,%1,%0", xoperands);
  1097.   else
  1098.     {
  1099.       xoperands[1]
  1100.     = gen_rtx (CONST_INT, VOIDmode, INTVAL (size) - INTVAL (align));
  1101.       cc_status.flags &= ~ CC_KNOW_HI_R31;
  1102.       output_asm_insn ("mov %1,%0", xoperands);
  1103.     }
  1104. #endif
  1105. }
  1106.  
  1107. /* Emit code to perform a block move.
  1108.  
  1109.    OPERANDS[0] is the destination.
  1110.    OPERANDS[1] is the source.
  1111.    OPERANDS[2] is the size.
  1112.    OPERANDS[3] is the known safe alignment.
  1113.    OPERANDS[4..6] are pseudos we can safely clobber as temps.  */
  1114.  
  1115. char *
  1116. output_block_move (operands)
  1117.      rtx *operands;
  1118. {
  1119.   /* A vector for our computed operands.  Note that load_output_address
  1120.      makes use of (and can clobber) up to the 8th element of this vector.  */
  1121.   rtx xoperands[10];
  1122.   rtx zoperands[10];
  1123.   static int movstrsi_label = 0;
  1124.   int i, j;
  1125.   rtx temp1 = operands[4];
  1126.   rtx alignrtx = operands[3];
  1127.   int align = INTVAL (alignrtx);
  1128.  
  1129.   xoperands[0] = operands[0];
  1130.   xoperands[1] = operands[1];
  1131.   xoperands[2] = temp1;
  1132.  
  1133.   /* We can't move more than four bytes at a time
  1134.      because we have only one register to move them through.  */
  1135.   if (align > 4)
  1136.     {
  1137.       align = 4;
  1138.       alignrtx = gen_rtx (CONST_INT, VOIDmode, 4);
  1139.     }
  1140.  
  1141.   /* Since we clobber untold things, nix the condition codes.  */
  1142.   CC_STATUS_INIT;
  1143.  
  1144.   /* Recognize special cases of block moves.  These occur
  1145.      when GNU C++ is forced to treat something as BLKmode
  1146.      to keep it in memory, when its mode could be represented
  1147.      with something smaller.
  1148.  
  1149.      We cannot do this for global variables, since we don't know
  1150.      what pages they don't cross.  Sigh.  */
  1151.   if (GET_CODE (operands[2]) == CONST_INT
  1152.       && INTVAL (operands[2]) <= 16
  1153.       && ! CONSTANT_ADDRESS_P (operands[0])
  1154.       && ! CONSTANT_ADDRESS_P (operands[1]))
  1155.     {
  1156.       int size = INTVAL (operands[2]);
  1157.       rtx op0 = xoperands[0];
  1158.       rtx op1 = xoperands[1];
  1159.  
  1160.       cc_status.flags &= ~CC_KNOW_HI_R31;
  1161.       if (align == 1)
  1162.     {
  1163.       if (memory_address_p (QImode, plus_constant (op0, size))
  1164.           && memory_address_p (QImode, plus_constant (op1, size)))
  1165.         {
  1166.           for (i = size-1; i >= 0; i--)
  1167.         {
  1168.           xoperands[0] = plus_constant (op0, i);
  1169.           xoperands[1] = plus_constant (op1, i);
  1170.           output_asm_insn ("ld.b %a1,r31\n\tst.b r31,%a0",
  1171.                    xoperands);
  1172.         }
  1173.           return "";
  1174.         }
  1175.     }
  1176.       else if (align == 2)
  1177.     {
  1178.       if (memory_address_p (HImode, plus_constant (op0, size))
  1179.           && memory_address_p (HImode, plus_constant (op1, size)))
  1180.         {
  1181.           for (i = (size>>1)-1; i >= 0; i--)
  1182.         {
  1183.           xoperands[0] = plus_constant (op0, i * 2);
  1184.           xoperands[1] = plus_constant (op1, i * 2);
  1185.           output_asm_insn ("ld.s %a1,r31\n\tst.s r31,%a0",
  1186.                    xoperands);
  1187.         }
  1188.           return "";
  1189.         }
  1190.     }
  1191.       else
  1192.     {
  1193.       if (memory_address_p (SImode, plus_constant (op0, size))
  1194.           && memory_address_p (SImode, plus_constant (op1, size)))
  1195.         {
  1196.           for (i = (size>>2)-1; i >= 0; i--)
  1197.         {
  1198.           xoperands[0] = plus_constant (op0, i * 4);
  1199.           xoperands[1] = plus_constant (op1, i * 4);
  1200.           output_asm_insn ("ld.l %a1,r31\n\tst.l r31,%a0",
  1201.                    xoperands);
  1202.         }
  1203.           return "";
  1204.         }
  1205.     }
  1206.     }
  1207.  
  1208.   /* This is the size of the transfer.
  1209.      Either use the register which already contains the size,
  1210.      or use a free register (used by no operands).  */
  1211.   output_size_for_block_move (operands[2], operands[4], alignrtx);
  1212.  
  1213. #if 0
  1214.   /* Also emit code to decrement the size value by ALIGN.  */
  1215.   zoperands[0] = operands[0];
  1216.   zoperands[3] = plus_constant (operands[0], align);
  1217.   output_load_address (zoperands);
  1218. #endif
  1219.  
  1220.   /* Generate number for unique label.  */
  1221.  
  1222.   xoperands[3] = gen_rtx (CONST_INT, VOIDmode, movstrsi_label++);
  1223.  
  1224.   /* Copy the increment (negative) to a register for bla insn.  */
  1225.  
  1226.   xoperands[4] = gen_rtx (CONST_INT, VOIDmode, - align);
  1227.   xoperands[5] = operands[5];
  1228.   output_asm_insn ("mov %4,%5", xoperands);
  1229.  
  1230.   xoperands[6] = operands[6];
  1231.   output_asm_insn ("adds %0,%2,%6", xoperands);
  1232.  
  1233.   /* Now the actual loop.
  1234.      In xoperands, elements 1 and 0 are the input and output vectors.
  1235.      Element 2 is the loop index.  Element 5 is the increment.  */
  1236.  
  1237.   if (align == 1)
  1238.     {
  1239.       output_asm_insn ("bla %5,%2,.Lm%3\n\tnop\n.Lm%3:", xoperands);
  1240.       output_asm_insn ("ld.b %1(%2),r31", xoperands);
  1241.       output_asm_insn ("adds %5,%6,%6", xoperands);
  1242.       output_asm_insn ("bla %5,%2,.Lm%3", xoperands);
  1243.       output_asm_insn ("st.b r31,0(%6)", xoperands);
  1244.     }
  1245.   if (align == 2)
  1246.     {
  1247.       output_asm_insn ("bla %5,%2,.Lm%3\n\tnop\n.Lm%3:", xoperands);
  1248.       output_asm_insn ("ld.s %1(%2),r31", xoperands);
  1249.       output_asm_insn ("adds %5,%6,%6", xoperands);
  1250.       output_asm_insn ("bla %5,%2,.Lm%3", xoperands);
  1251.       output_asm_insn ("st.s r31,0(%6)", xoperands);
  1252.     }
  1253.   if (align == 4)
  1254.     {
  1255.       output_asm_insn ("bla %5,%2,.Lm%3\n\tnop\n.Lm%3:", xoperands);
  1256.       output_asm_insn ("ld.l %1(%2),r31", xoperands);
  1257.       output_asm_insn ("adds %5,%6,%6", xoperands);
  1258.       output_asm_insn ("bla %5,%2,.Lm%3", xoperands);
  1259.       output_asm_insn ("st.l r31,0(%6)", xoperands);
  1260.     }
  1261.  
  1262.   return "";
  1263. }
  1264.  
  1265. /* Output a delayed branch insn with the delay insn in its
  1266.    branch slot.  The delayed branch insn template is in TEMPLATE,
  1267.    with operands OPERANDS.  The insn in its delay slot is INSN.
  1268.  
  1269.    As a special case, since we know that all memory transfers are via
  1270.    ld/st insns, if we see a (MEM (SYMBOL_REF ...)) we divide the memory
  1271.    reference around the branch as
  1272.  
  1273.     orh ha%x,r0,r31
  1274.     b ...
  1275.     ld/st l%x(r31),...
  1276.  
  1277.    As another special case, we handle loading (SYMBOL_REF ...) and
  1278.    other large constants around branches as well:
  1279.  
  1280.     orh h%x,r0,%0
  1281.     b ...
  1282.     or l%x,%0,%1
  1283.  
  1284.    */
  1285.  
  1286. char *
  1287. output_delayed_branch (template, operands, insn)
  1288.      char *template;
  1289.      rtx *operands;
  1290.      rtx insn;
  1291. {
  1292.   extern rtx recog_operand[];
  1293.   rtx src = XVECEXP (PATTERN (insn), 0, 1);
  1294.   rtx dest = XVECEXP (PATTERN (insn), 0, 0);
  1295.  
  1296.   if (GET_CODE (src) == SYMBOL_REF || GET_CODE (src) == CONST
  1297.       || (GET_CODE (src) == CONST_INT
  1298.       && !(SMALL_INT (src) || (INTVAL (src) & 0x3ff) == 0)))
  1299.     {
  1300.       rtx xoperands[2];
  1301.       xoperands[0] = dest;
  1302.       xoperands[1] = src;
  1303.  
  1304.       /* Output the `orh' insn.  */
  1305.       output_asm_insn ("orh h%%%1,r0,%0", xoperands);
  1306.  
  1307.       /* Output the branch instruction next.  */
  1308.       output_asm_insn (template, operands);
  1309.  
  1310.       /* Now output the `or' insn.  */
  1311.       output_asm_insn ("or l%%%1,%0,%0", xoperands);
  1312.     }
  1313.   else if ((GET_CODE (src) == MEM
  1314.         && CONSTANT_ADDRESS_P (XEXP (src, 0)))
  1315.        || (GET_CODE (dest) == MEM
  1316.            && CONSTANT_ADDRESS_P (XEXP (dest, 0))))
  1317.     {
  1318.       rtx xoperands[2];
  1319.       char *split_template;
  1320.       xoperands[0] = dest;
  1321.       xoperands[1] = src;
  1322.  
  1323.       /* Output the `orh' insn.  */
  1324.       if (GET_CODE (src) == MEM)
  1325.     {
  1326.       if (! ((cc_prev_status.flags & CC_KNOW_HI_R31)
  1327.          && (cc_prev_status.flags & CC_HI_R31_ADJ)
  1328.          && cc_prev_status.mdep == XEXP (operands[1], 0)))
  1329.         output_asm_insn ("orh ha%%%m1,r0,r31", xoperands);
  1330.       split_template = load_opcode (GET_MODE (dest),
  1331.                     "l%%%m1(r31),%0", src);
  1332.     }
  1333.       else
  1334.     {
  1335.       if (! ((cc_prev_status.flags & CC_KNOW_HI_R31)
  1336.          && (cc_prev_status.flags & CC_HI_R31_ADJ)
  1337.          && cc_prev_status.mdep == XEXP (operands[0], 0)))
  1338.         output_asm_insn ("orh ha%%%m0,r0,r31", xoperands);
  1339.       split_template = store_opcode (GET_MODE (dest),
  1340.                      "%r1,l%%%m0(r31)", src);
  1341.     }
  1342.  
  1343.       /* Output the branch instruction next.  */
  1344.       output_asm_insn (template, operands);
  1345.  
  1346.       /* Now output the load or store.
  1347.      No need to do a CC_STATUS_INIT, because we are branching anyway.  */
  1348.       output_asm_insn (split_template, xoperands);
  1349.     }
  1350.   else
  1351.     {
  1352.       extern char *insn_template[];
  1353.       extern char *(*insn_outfun[])();
  1354.       extern int insn_n_operands[];
  1355.       extern rtx alter_subreg();
  1356.       int insn_code_number;
  1357.       rtx pat = gen_rtx (SET, VOIDmode, dest, src);
  1358.       rtx delay_insn = gen_rtx (INSN, VOIDmode, 0, 0, 0, pat, -1, 0, 0);
  1359.       int i;
  1360.  
  1361.       /* Output the branch instruction first.  */
  1362.       output_asm_insn (template, operands);
  1363.  
  1364.       /* Now recognize the insn which we put in its delay slot.
  1365.      We must do this after outputing the branch insn,
  1366.      since operands may just be a pointer to `recog_operand'.  */
  1367.       insn_code_number = recog (pat, delay_insn);
  1368.       if (insn_code_number == -1)
  1369.     abort ();
  1370.  
  1371.       for (i = 0; i < insn_n_operands[insn_code_number]; i++)
  1372.     {
  1373.       if (GET_CODE (recog_operand[i]) == SUBREG)
  1374.         recog_operand[i] = alter_subreg (recog_operand[i]);
  1375.     }
  1376.  
  1377.       /* Now get the template for what this insn would
  1378.      have been, without the branch.  Its operands are
  1379.      exactly the same as they would be, so we don't
  1380.      need to do an insn_extract.  */
  1381.       template = insn_template[insn_code_number];
  1382.       if (template == 0)
  1383.     template = (*insn_outfun[insn_code_number]) (recog_operand, delay_insn);
  1384.       output_asm_insn (template, recog_operand);
  1385.     }
  1386.   CC_STATUS_INIT;
  1387.   return "";
  1388. }
  1389.  
  1390. /* Output a newly constructed insn DELAY_INSN.  */
  1391. char *
  1392. output_delay_insn (delay_insn)
  1393.      rtx delay_insn;
  1394. {
  1395.   char *template;
  1396.   extern rtx recog_operand[];
  1397.   extern char call_used_regs[];
  1398.   extern char *insn_template[];
  1399.   extern int insn_n_operands[];
  1400.   extern char *(*insn_outfun[])();
  1401.   extern rtx alter_subreg();
  1402.   int insn_code_number;
  1403.   extern int insn_n_operands[];
  1404.   int i;
  1405.  
  1406.   /* Now recognize the insn which we put in its delay slot.
  1407.      We must do this after outputing the branch insn,
  1408.      since operands may just be a pointer to `recog_operand'.  */
  1409.   insn_code_number = recog_memoized (delay_insn);
  1410.   if (insn_code_number == -1)
  1411.     abort ();
  1412.  
  1413.   /* Extract the operands of this delay insn.  */
  1414.   INSN_CODE (delay_insn) = insn_code_number;
  1415.   insn_extract (delay_insn);
  1416.  
  1417.   /* It is possible that this insn has not been properly scaned by final
  1418.      yet.  If this insn's operands don't appear in the peephole's
  1419.      actual operands, then they won't be fixed up by final, so we
  1420.      make sure they get fixed up here.  -- This is a kludge.  */
  1421.   for (i = 0; i < insn_n_operands[insn_code_number]; i++)
  1422.     {
  1423.       if (GET_CODE (recog_operand[i]) == SUBREG)
  1424.     recog_operand[i] = alter_subreg (recog_operand[i]);
  1425.     }
  1426.  
  1427. #ifdef REGISTER_CONSTRAINTS
  1428.   if (! constrain_operands (insn_code_number))
  1429.     abort ();
  1430. #endif
  1431.  
  1432.   cc_prev_status = cc_status;
  1433.  
  1434.   /* Update `cc_status' for this instruction.
  1435.      The instruction's output routine may change it further.
  1436.      If the output routine for a jump insn needs to depend
  1437.      on the cc status, it should look at cc_prev_status.  */
  1438.  
  1439.   NOTICE_UPDATE_CC (PATTERN (delay_insn), delay_insn);
  1440.  
  1441.   /* Now get the template for what this insn would
  1442.      have been, without the branch.  */
  1443.  
  1444.   template = insn_template[insn_code_number];
  1445.   if (template == 0)
  1446.     template = (*insn_outfun[insn_code_number]) (recog_operand, delay_insn);
  1447.   output_asm_insn (template, recog_operand);
  1448.   return "";
  1449. }
  1450.  
  1451.